import { World } from "../world/World";

import { IUpdatable } from "../interface/IUpdatable";
import { IInputReceiver } from "../interface/IInputReceiver";

export class InputManager implements IUpdatable {

    public updateOrder: number = 3;

    public world: World;
    public domElement: HTMLElement;

    public pointerLock: boolean;
    public isLocked: boolean;
    public inputReceiver: IInputReceiver | undefined;

    constructor ( world: World, domElement: HTMLElement ) {
        this.world = world;
        this.pointerLock = world.params.Pointer_Lock;
        this.domElement = domElement || document.body;
        this.isLocked = false;

        this.domElement.addEventListener( "mousedown", this.onmousedown, false );
        document.addEventListener( "wheel", this.onwheel, false );
        document.addEventListener( "pointerlockchange", this.onpointerlockchange, false );
        document.addEventListener( "pointerlockerror", this.onpointerlockerror, false );

        document.addEventListener( "keydown", this.onkeydown, false );
        document.addEventListener( "keyup", this.onkeyup, false );

        world.registerUpdatable( this );
    }

    update ( timeStep: number, unscaledTimeStep: number ): void {
        if ( this.inputReceiver === undefined && this.world !== undefined && this.world.cameraOperator !== undefined ) {
            this.setInputReceiver( this.world.cameraOperator );
        }

        if ( this.inputReceiver !== undefined ) {
            this.inputReceiver.inputReceiverUpdate( unscaledTimeStep );
        }
    }

    setInputReceiver ( receiver: IInputReceiver ) {
        this.inputReceiver = receiver;
        this.inputReceiver.inputReceiverInit();
    }

    setPointerlock ( enabled: boolean ) {
        this.pointerLock = enabled;
    }

    onpointerlockchange = ( event: Event ) => {
        if ( document.pointerLockElement === this.domElement ) {
            this.domElement.addEventListener( "mousemove", this.onmousemove, false );
            this.domElement.addEventListener( "mouseup", this.onmouseup, false );
            this.isLocked = true;
        } else {
            this.domElement.removeEventListener( "mousemove", this.onmousemove, false );
            this.domElement.removeEventListener( "mouseup", this.onmouseup, false );
            this.isLocked = false;
        }
    };

    onpointerlockerror = ( event: Event ) => {
        // console.error( 'PointerLockControls: Unable to use Pointer Lock API' );
    };

    onmousedown = ( event: MouseEvent ) => {

        if ( this.pointerLock ) {
            try {
                this.domElement.requestPointerLock();
            } catch ( error ) {
                // console.log( "用户在完成此请求之前已退出鼠标锁定" );
            }
        } else {
            this.domElement.addEventListener( "mousemove", this.onmousemove, false );
            this.domElement.addEventListener( "mouseup", this.onmouseup, false );
        }

        if ( this.inputReceiver !== undefined ) {
            this.inputReceiver.handleMouseButton( event, "mouse" + event.button, true );
        }
    };

    onmousemove = ( event: MouseEvent ) => {
        if ( this.inputReceiver !== undefined ) {
            this.inputReceiver.handleMouseMove( event, event.movementX, event.movementY );
        }
    };

    onmouseup = ( event: MouseEvent ) => {
        if ( !this.pointerLock ) {
            this.domElement.removeEventListener( "mousemove", this.onmousemove, false );
            this.domElement.removeEventListener( "mouseup", this.onmouseup, false );
        }
        if ( this.inputReceiver !== undefined ) {
            this.inputReceiver.handleMouseButton( event, "mouse" + event.button, false );
        }
    };

    onkeydown = ( event: KeyboardEvent ) => {
        if ( this.inputReceiver !== undefined ) {
            this.inputReceiver.handleKeyboardEvent( event, event.code, true );
        }
    };

    onkeyup = ( event: KeyboardEvent ) => {
        if ( this.inputReceiver !== undefined ) {
            this.inputReceiver.handleKeyboardEvent( event, event.code, false );
        }
    };

    onwheel = ( event: WheelEvent ) => {
        if ( this.inputReceiver !== undefined ) {
            this.inputReceiver.handleMouseWheel( event, event.deltaY );
        }
    };

}